package com.lingjtx.common.influx.common;

import com.alibaba.fastjson2.JSON;
import com.lingjtx.common.influx.annotation.Column;
import com.lingjtx.common.influx.annotation.Measurement;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

public class LineProtocolBuilder {

    public static String build(Object body) {
        if (body == null) return null;

        Class<?> clazz = body.getClass();
        Measurement measurement = clazz.getDeclaredAnnotation(Measurement.class);
        if (measurement == null) return null;

        StringBuilder tags = new StringBuilder();
        StringBuilder fields = new StringBuilder();
        long timestamp = System.currentTimeMillis();

        String measurementName = measurement.name();
        Field[] declaredFields = clazz.getDeclaredFields();

        for (Field field : declaredFields) {
            Column column = field.getAnnotation(Column.class);
            if (column == null) continue;

            String fieldName = !column.name().isEmpty() ? column.name() : field.getName();
            Object value = getFieldValue(body, field);

            if (value == null) continue;

            try {
                if (column.tag()) {
                    tags.append(escape(fieldName))
                            .append("=")
                            .append(escape(value.toString()))
                            .append(",");
                } else if (column.timestamp()) {
                    if (value instanceof Date) {
                        timestamp = ((Date) value).getTime();
                    } else if (value instanceof Long) {
                        timestamp = (Long) value;
                    }
                } else {
                    fields.append(escape(fieldName))
                            .append("=")
                            .append(formatFieldValue(value))
                            .append(",");
                }
            } catch (Exception e) {
                throw new RuntimeException("Influx Error processing field: " + fieldName, e);
            }
        }

        // remove trailing commas
        if (!tags.isEmpty()) tags.deleteCharAt(tags.length() - 1);
        if (!fields.isEmpty()) fields.deleteCharAt(fields.length() - 1);

        return String.format("%s%s %s %d",
                measurementName,
                !tags.isEmpty() ? "," + tags : "",
                fields,
                timestamp);
    }

    private static Object getFieldValue(Object obj, Field field) {
        try {
            String name = field.getName();
            String methodName = "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
            Method method = obj.getClass().getMethod(methodName);
            return method.invoke(obj);
        } catch (Exception e) {
            return null;
        }
    }

    private static String escape(String s) {
        // escape InfluxDB special characters in tags/field keys/values
        return s.replace(" ", "\\ ")
                .replace(",", "\\,")
                .replace("=", "\\=");
    }

    private static String formatFieldValue(Object value) {
        if (value instanceof String) {
            return "\"" + value.toString().replace("\"", "\\\"") + "\"";
        } else if (value instanceof Number || value instanceof Boolean) {
            return value.toString();
        } else if (value instanceof Collection || value instanceof Map) {
            return "\"" + JSON.toJSONString(value) + "\"";
        } else {
            return "\"" + value.toString().replace("\"", "\\\"") + "\"";
        }
    }
}
